package net.cyndeline.rldungeon.dgs.strategy.pointlessArea.algorithmModules

import scalax.collection.immutable.Graph
import net.cyndeline.rldungeon.dgs.strategy.help.{CollapsedEdge, CollapsedNode}
import net.cyndeline.rldungeon.dgs.graph.{DGSFunctionality, Room}
import scalax.collection.GraphEdge.UnDiEdge
import scalax.collection.GraphPredef.OuterEdge
import net.cyndeline.rlgraph.util.VertexReplacer
import net.cyndeline.rldungeon.dgs.EdgeCopyFactory

/**
 * Used for injection.
 */
trait RoomStatusModifierI {
  def markRoomsAsMeaningful[VType <: Room[VType], EType[X] <: UnDiEdge[X] with DGSFunctionality[X, EType] with OuterEdge[X, EType]]
                            (graph: Graph[VType, EType],
                            cycleCollapsedGraph: Graph[CollapsedNode[VType], CollapsedEdge[VType]#Inner],
                            edgeFactory: EdgeCopyFactory[VType, EType]): Graph[VType, EType]
}

/**
 * Takes every represented room in a collapsed graph and marks them as meaningful in the represented graph.
 *
 * This is the final step in removing pointless areas, and works since the collapsed graph is trimmed such that
 * every remaining node will either contain a meaningful room, or lead to one.
 */
class RoomStatusModifier[VType <: Room[VType], EType[X] <: UnDiEdge[X] with DGSFunctionality[X, EType] with OuterEdge[X, EType]]
  extends RoomStatusModifierI {

  /**
   * Takes every pointless room in a collapsed graph and replaces it with a meaningful room in its represented graph.
   * @param graph An original non-collapsed graph representing an entire level.
   * @param cycleCollapsedGraph A cycle-collapsed graph whose represented rooms make up a subset of the original graph.
   * @return A copy of the original graph with every room appearing in the collapsed graph set as meaningful.
   */
  def markRoomsAsMeaningful[VType <: Room[VType], EType[X] <: UnDiEdge[X] with DGSFunctionality[X, EType] with OuterEdge[X, EType]]
                            (graph: Graph[VType, EType],
                            cycleCollapsedGraph: Graph[CollapsedNode[VType], CollapsedEdge[VType]#Inner],
                            edgeFactory: EdgeCopyFactory[VType, EType]): Graph[VType, EType] = {
    val vertexReplacer = new VertexReplacer[VType, EType](edgeFactory)
    var currentGraph = graph

    val collapsedNodes: Iterator[cycleCollapsedGraph.NodeT] = cycleCollapsedGraph.nodes.iterator

    while (collapsedNodes.hasNext) {
      val cn = collapsedNodes.next()
      val representedRooms = cn.vertexCollection.iterator

      while (representedRooms.hasNext) {
        val room = representedRooms.next()

        if (room.isPointless) {
          if (!currentGraph.contains(room)) {
            throw new IllegalArgumentException("The full graph " + graph + " did not contain the room " + room + " as represented in " + cycleCollapsedGraph)
          } else {
            val meaningfulRoom = room.withPointlessStatus(false)
            currentGraph = vertexReplacer.replace(room, meaningfulRoom, currentGraph)
          }
        }
      }
    }

    currentGraph
  }

}
